package main

import "fmt"

/*
	怎样判断一个变量的类型
		使用“类型断言”表达式
		value, ok := interface{}(container).([]string)
		这里有一条赋值语句。在赋值符号的右边，是一个类型断言表达式。
		它包括了用来把container变量的值转换为空接口值的interface{}(container)。
		以及一个用于判断前者的类型是否为切片类型 []string 的 .([]string)。



	说明：
		1.类型断言表达式的语法形式是x.(T)。其中的x代表要被判断类型的值。这个值当下的类型必须是接口类型的。
		2.所以，当这里的container变量类型不是任何的接口类型时，我们就需要先把它转成某个接口类型的值。

	一对不包裹任何东西的花括号，除了可以代表空的代码块之外，还可以用于表示不包含任何内容的数据结构（或者说数据类型）。

	struct{}：
		它就代表了不包含任何字段和方法的、空的结构体类型。

	interface{}：
		代表了不包含任何方法定义的、空的接口类型。

	对于一些集合类的数据类型来说，{}还可以用来表示其值不包含任何元素，比如空的切片值[]string{}，以及空的字典值map[int]string{}。


问题 1.类型转换规则中有哪些值得注意的地方？

	a.首先，对于整数类型值、整数常量之间的类型转换，原则上只要源值在目标类型的可表示范围内就是合法的。
		比如，之所以uint8(255)可以把无类型的常量255转换为uint8类型的值，是因为255在 [0, 255] 的范围内。

		但需要特别注意的是，源整数类型的可表示范围较大，而目标类型的可表示范围较小的情况，比如把值的类型从int16转换为int8。

			var srcInt = int16(-255)
			dstInt := int8(srcInt)
		变量srcInt的值是int16类型的-255，而变量dstInt的值是由前者转换而来的，类型是int8。
		int16类型的可表示范围可比int8类型大了不少。问题是，dstInt的值是多少？

		整数在 Go 语言以及计算机中都是以补码的形式存储的。这主要是为了简化计算机对整数的运算过程。补码其实就是原码各位求反再加 1。
		比如，int16类型的值-255的补码是1111111100000001。如果我们把该值转换为int8类型的值，
		那么 Go 语言会把在较高位置（或者说最左边位置）上的 8 位二进制数直接截掉，从而得到00000001。
		又由于其最左边一位是0，表示它是个正整数，以及正整数的补码就等于其原码，所以dstInt的值就是1。

    注意: 当整数值的类型的有效范围由宽变窄时，只需在补码形式下截掉一定数量的高位二进制数即可。

  	b.虽然直接把一个整数值转换为一个string类型的值是可行的，但值得关注的是，被转换的整数值应该可以代表一个有效的 Unicode 代码点，
		否则转换的结果将会是"�"（仅由高亮的问号组成的字符串值）。

    c.关于string类型与各种切片类型之间的互转的。
		一个值在从string类型向[]byte类型转换时代表着以 UTF-8 编码的字符串会被拆分成零散、独立的字节。
			string ="你好"
			string([]byte{'\xe4', '\xbd', '\xa0', '\xe5', '\xa5', '\xbd'}) // 你好

		一个值在从string类型向[]rune类型转换时代表着字符串会被拆分成一个个 Unicode 字符。
			string ="你好"
			string([]rune{'\u4F60', '\u597D'}) // 你好

问题 2. 什么是别名类型？什么是潜在类型？
	a.别名类型
		type MyString = string
		这条声明语句表示，MyString是string类型的别名类型。顾名思义，别名类型与其源类型的区别恐怕只是在名称上，它们是完全相同的。

		Go 语言内建的基本类型中就存在两个别名类型。byte是uint8的别名类型，而rune是int32的别名类型。

	b.类型再定义
		type MyString2 string // 注意，这里没有等号。
		MyString2和string就是两个不同的类型了。这里的MyString2是一个新的类型，不同于其他任何类型。这种方式也可以被叫做对类型的再定义。

		对于这里的类型再定义来说，string可以被称为MyString2的潜在类型。潜在类型的含义是，某个类型在本质上是哪个类型。

		潜在类型相同的不同类型的值之间是可以进行类型转换的。因此，MyString2类型的值与string类型的值可以使用类型转换表达式进行互转。

		但对于集合类的类型[]MyString2与[]string来说这样做却是不合法的，因为[]MyString2与[]string的潜在类型不同，分别是[]MyString2和[]string。

*/

var container = []string{"zero","one","two"}

func main() {

	container :=map[int]string{0:"zero", 1:"one", 2:"two"}

	_,ok := interface{}(container).([]string)
	if ok {
		fmt.Println("container type is slice")
	} else {
		fmt.Println("container type is map")
	}

	fmt.Printf("The element is %q.\n", container[1])

}
